/******************** (C) COPYRIGHT 2004 STMicroelectronics ********************
* File Name          : ymodem.c
* Author             : MCD Application Team
* Date First Issued  : 10/25/2004
* Description        : This file provides all the software functions relatd to 
*                    : the ymodem protocol
********************************************************************************
* History:
*  10/25/2004 : Created
*  11/24/2004 : IAP Version 1.0
********************************************************************************
THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS WITH
CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. AS A 
RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR 
CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT OF SUCH 
SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN
IN CONNECTION WITH THEIR PRODUCTS.
********************************************************************************/
#include "ymodem.h"
#include "common.h"
#include "2440lib.h"
#include "Uart_fifo.h"


RAW_S8 file_name[FILE_NAME_LENGTH];
/*******************************************************************************
* Function Name  : Receive_Byte
* Description    : Receive byte from sender
* Input 1        : Character
* Input 2        : Timeout
* Return         :  0   --      Byte received                           
*                : -1   --      Timeout   
*******************************************************************************/

static RAW_S8 Receive_Byte (RAW_U8 *c, RAW_U32 timeout)
{
	RAW_U32 len;
	
	len = uart_receive_t(c, 1, timeout);
	
	if(len == 1)
	{
		return 0;
	}
	else
	{
		return -1;
	}
}

/*******************************************************************************
* Function Name  : Send_Byte
* Description    : Send a byte 
* Input          : Character
* Return         :  0   --      Byte sent                           
*******************************************************************************/
static RAW_U32 Send_Byte (RAW_U8 c)
{
	Uart_SendByte(c);
	return 0;
}

/*******************************************************************************
* Function Name  : Receive_Packet
* Description    : Receive a packet from sender 
* Input 1        : Data
* Input 2        : Length
* Input 3        : Timeout
* Return         :   0  --      normally return                         
*                :  -1  --      timeout or packet error                 
*                :   1  --      abort by user                           
*                : *length:                                                
*                :   0  --      end of transmission                    
*                :  -1  --      abort by sender                         
*                :  >0  --      packet length                                      
*******************************************************************************/
static RAW_S8 Receive_Packet (RAW_U8 *data, RAW_S32 *length, RAW_U32 timeout)
{
	RAW_U32 i, packet_size;
	RAW_U8 c=0;
	*length = 0;
	if (Receive_Byte(&c, timeout) != 0)
	{
		return -1;
	}

	switch (c)
	{
	case SOH:
		packet_size = PACKET_SIZE;
	break;
	case STX:
		packet_size = PACKET_1K_SIZE;
	break;
	case EOT:
	return 0;
	case CAN:
		if ((Receive_Byte(&c, timeout) == 0) && (c == CAN))
		{
			*length = -1;
			return 0;
		}
		else
		{
			return -1;
		}
	case ABORT1:
	case ABORT2:
		return 1;
	default:
		return -1;
	}
	*data = c;
	for (i = 1; i < (packet_size + PACKET_OVERHEAD); i ++)
	{
		if (Receive_Byte(data + i, timeout) != 0)
		{
			return -1;
		}
	}
	if (data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff))
	{
		return -1;
	}
	*length = packet_size;
	return 0;
}
/*******************************************************************************
* Function Name  : Ymodem_Receive
* Description    : Receive a file using the ymodem protocol 
* Input          : Address of the first byte 
* Return         : The size of the file                                                               
*******************************************************************************/
RAW_S32 Ymodem_Receive (RAW_U8 *buf)
{
  RAW_U8 packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;
  RAW_U32 i, session_done, file_done, packets_received, errors, session_begin, size = 0;
  RAW_S32 packet_length;

  for (session_done = 0, errors = 0, session_begin = 0; ;)
  {
    for (packets_received = 0, file_done = 0, buf_ptr = buf; ;)
    {
      switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT))
      {
        case 0:
          errors = 0;
           switch (packet_length)
           {
             case -1:    /* abort by sender */
               Send_Byte(ACK);
               return 0;
             case 0:     /* end of transmission */
               Send_Byte(ACK);
               file_done = 1;
               break;
             default:    /* normal packet */
               if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff))
               {
                 Send_Byte(NAK);
               }
               else
               {
                 if (packets_received == 0)                  /* filename packet */
                 {
                   if (packet_data[PACKET_HEADER] != 0)    /* filename packet has valid data */
                   {
                     for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
                     {
                       file_name[i++] = *file_ptr++;
                     }
                     file_name[i++] = '\0';
                     for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);)
                     {
                       file_size[i++] = *file_ptr++;
                     }
                     file_size[i++] = '\0';
                     Str2Int(file_size, &size);
                     Send_Byte(ACK);
                     Send_Byte(CRC16);
                   }
                   else                                    /* filename packet is empty; end session */
                   {
                     Send_Byte(ACK);
                     file_done = 1;
                     session_done = 1;
                     break;
                   }
                 }
                 else                                        /* data packet */
                 {
                   memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
                   buf_ptr += packet_length;
                   Send_Byte(ACK);
                 }
                 packets_received ++;
                 session_begin = 1;
               }
             }
             break;
           case 1:
             Send_Byte(CAN);
             Send_Byte(CAN);
             return -1;
           default:
             if (session_begin > 0)
             {
               errors ++;
             }
             if (errors > MAX_ERRORS)
             {
               Send_Byte(CAN);
               Send_Byte(CAN);
               return 0;
             }
             Send_Byte(CRC16);
             break;
         }
         if (file_done != 0)
         {
         break;
       }
     }
     if (session_done != 0)
     {
       break;
     }
  }  
  return (RAW_S32)size;
}
/*******************(C)COPYRIGHT 2004 STMicroelectronics *****END OF FILE****/

